library(tidyverse)
── Attaching core tidyverse packages ───────────────
✔ dplyr 1.1.2 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.2 ✔ tibble 3.2.1
✔ lubridate 1.9.2 ✔ tidyr 1.3.0
✔ purrr 1.0.1 ── Conflicts ────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(usmap)
library(ggplot2)
library(broom)
library(lubridate)
library(plotly)
Registered S3 method overwritten by 'data.table':
method from
print.data.table
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
Attaching package: ‘plotly’
The following object is masked from ‘package:ggplot2’:
last_plot
The following object is masked from ‘package:stats’:
filter
The following object is masked from ‘package:graphics’:
layout
### Read in data
marathon_usa_sex_pace <- read_csv("data/marathon_usa_sex_pace.csv")
Rows: 102 Columns: 4── Column specification ───────────────────────────────────────────────────
Delimiter: ","
chr (2): state, Sex
dbl (2): number, mean_pace
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
### create a choropleth
p <- plot_usmap(data = marathon_usa_sex_pace, values = "number", color = "black",)+scale_size_continuous(range = c(min(marathon_usa_sex_pace$n), max(marathon_usa_sex_pace$n)))+ scale_fill_continuous(
low = "#FEEBE7", high = "red", name = "Total", label = scales::comma
) + theme(legend.position = "right")+
facet_wrap(~ Sex,ncol = 1,labeller = as_labeller(c('F' = "Number of Female Pariticpants", 'M' = "Number of Male Participants"))) +ggtitle(label = "Boston Marathon 2017")
Warning: Unknown or uninitialised column: `n`.Warning: no non-missing arguments to min; returning InfWarning: Unknown or uninitialised column: `n`.Warning: no non-missing arguments to max; returning -Inf
p2<-p + theme(
legend.position = c(1, .3),
legend.background = element_rect(fill = "white", colour = NA),
strip.background = element_blank(),
plot.title = element_text(size=20),
strip.text = element_text(size=15),
panel.spacing = unit(2, "lines"),
plot.caption = element_text("State of Participants Origin")
)
#ggplotly(p2)
####model
### read in and process data
marathon <- read_csv("data/marathon.csv")
Rows: 26410 Columns: 21── Column specification ────────────────────────────
Delimiter: ","
chr (6): Bib, Name, M/F, City, State, Country
dbl (4): Age, Overall, Gender, Division
time (11): fiveK, tenK, fifteenK, twentyK, Half,...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
marathon <- na.omit(marathon)
marathon$Half<- hms(marathon$Half)
marathon$OfficialTime<- hms(marathon$OfficialTime)
marathon$tenK<- hms(marathon$tenK)
marathon$thirtyK<- hms(marathon$thirtyK)
marathon$Pace<- hms(marathon$Pace)
marathon$Half<- as.numeric(marathon$Half)
marathon$OfficialTime<- as.numeric(marathon$OfficialTime)
marathon$tenK<- as.numeric(marathon$tenK)
marathon$thirtyK<- as.numeric(marathon$thirtyK)
marathon$Pace<- as.numeric(marathon$Pace)
### create models
m2_model <- lm(OfficialTime ~ tenK + Half + thirtyK,
data = marathon)
tidy(m2_model)
m2_coefs <- tidy(m2_model, conf.int = TRUE) %>%
filter(term != "(Intercept)")
#m2_coefs
m3_model <- lm(OfficialTime ~ tenK + Half + thirtyK+Age,
data = marathon)
tidy(m3_model)
m3_coefs <- tidy(m3_model, conf.int = TRUE) %>%
filter(term != "(Intercept)")
#m3_coefs
###create coefficent plot
lables2<-c("30K","10K", "Half Race","Age")
pco<-ggplot(m3_coefs,
aes(x = estimate,
y = fct_rev(term))) +
geom_pointrange(aes(xmin = conf.low,
xmax = conf.high, color=fct_rev(term)),size=.75) +
geom_vline(xintercept = 0,
color = "purple") +
scale_color_brewer(palette="Set1")+
theme_minimal()+labs(title = "Linear Model Coefficents for Finish Time", x= "Estimate Coefficent", y="Distance Run")+scale_color_discrete(name="Distance Run", labels=lables2)+scale_y_discrete(labels=lables2)
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
#pco
ggplotly(p2)
Spatial Visualization
What I originally wanted to make was a world map showing the
participants origins. However when going through the data it become
apparent that there wasn’t high number participants represented outside
the USA in comparison to inside the USA. So I switched to a USA map and
decided to show the participants by state. I further divided the data by
Sex to see if there were any visual differences. The steps I took were
filtering out the non USA participants and then further dividing them up
by sex. I then summed the amount of each per state and created a new
data frame to graph the data. Finally I wanted to have something
interactive so I decided to use ggplotly so you can see the individual
numbers per state.
Looking at this map you can see two things. That the general
distribution of male and female participants is very similar as the
colors for each state look similar. Also you can see which states have
the most participants with Massachusetts having the most. This makes
sense because the marathon is hosted in Boston. However whats
interesting the second state is California. I think this is interesting
because California is so far away from Massachusetts. It’s also fun to
see that they also had participants from Alaska and Hawaii.
I kept the design simple and used a base red color to make the
populations stand out more, and kept it to one color. I made the title
left aligned because the viewers eyes tend to view the left. I used a
facet style graph to show side by side the male and female participants
in a way that was easy to see. I used ggploty to make the map
interactive so you can hover over every plot and see the numbers. This
draws in the user to use the map.
ggplot() +
geom_smooth(aes(x = tenK, y = OfficialTime), data = m2_model,
method = "lm", se = FALSE, color = "red4") +
geom_smooth(aes(x = Half, y = OfficialTime), data = m2_model,
method = "lm", se = FALSE, color = "blue4") +
geom_smooth(aes(x = thirtyK, y = OfficialTime), data = m2_model,
method = "lm", se = FALSE, color = "green4") +
geom_point(aes(x = tenK, y = OfficialTime), data = m2_model, color = "red",alpha = 0.02)+
geom_point(aes(x = Half, y = OfficialTime), data = m2_model, color = "blue",alpha = 0.02) +
geom_point(aes(x = thirtyK, y = OfficialTime), data = m2_model, color = "green",alpha = 0.02)+
annotate('text', x = 5100, y = 27000, label = 'Ten K',size = 5,angle='68', color= 'red4')+
annotate('text', x = 11000, y = 25500, label = 'Half Race',size = 5,angle='51', color= 'blue4')+
annotate('text', x = 18000, y = 27500, label = 'Thrity K',size = 5,angle='41', color= 'green4')+labs(
title = "Linear Model Line for Offical Time by Distance Time", x= "Distance Time in Seconds", y="Finish Time in Seconds")+theme_minimal()

NA
NA
Linear Model Line Plot
For the model I originally planed to create a line with
geom_smooth and a linear model. I created a linear model then used the
linear model data to draw three lines with its associated plot cloud. I
also had to convert the time to seconds. I also originally wanted to
plot age but it didn’t turn out good.
Looking at the data you can see the plot cloud for the three
different distances over Finish time. You can see where each distance as
a linear model and how it associates with what it predicts where the
finish time should be compared to the time at the associated distance.
You can see the slopes of the predicted lines. The story you can tell
here is you can follow the line and see if you passed a distance at x
time your finish them will likely be y time. A runner can use this to
target times they need to meet. This is followed for each of the three
distances. I had difficulty here adding Age as a component it doesn’t
seem to create a usable line.
I continued to keep the design simple with bright colors to clash
against the white background. I’m a fan of theme_minimal and think it
does a good job of decluttering the graph. I added a opacity to the plot
points because they were so thick you couldn’t see the lines. For each
line I added an annotation to identify which line goes to with variable
distance.
pco

Model Visualization Coefficient Plot
For the model I originally planed to create a coefficient plot. I
wanted to have more elements originally but I decided to keep it simple
and limit it to four plot elements, early in the race, middle of the
race and late in the race and finally age. I found that adding more
distances was somewhat redundant and complicated the model. The steps I
took were running the variables through a linear model, then getting the
coefficients and converting the information into to tidy data.
Looking at this map you can see the coefficients and it has a
vertical line at zero. Points that are close to the zero don’t have much
bearing on the outcome. Looking at the plots you can see that 10K is
close to the zero line. You can also see that Half race has a value of
-1.3 which has a negative influence on the outcome and that 30K is 2.3
positive and has very strong bearing on the overcome of the Finish Time.
The Story here is that how you do early in the race has much less effect
on your finishing time than how you do later in the race. One last
coefficient I threw in here for the graph is Age, you see that Age age
has large bearing on your Finish Time. Difficulties I had were the
linear model function in R would not take it in time properly I had to
change all the times to seconds.
Again I kept design of the graph simple. I have a line in the
graph to easily show where zero is. the points are large and easy to
see. The theme used here is a minimal theme. I used a SET2 palette to
make the colors pop against the white background.
Interactive Visualization
Go to Interactive_Viz.R and select run app to load up interactive
bar graph. Below is a screenshot of the app for reference purposes.

Shiny App requires loading up
Go to Interactive_Viz.R and select run app to load up Shiny
interactive bar graph. Above is a screenshot of the app for reference
purposes.
For my final visualization I wanted to create a shiny
application. I decided on displaying the running information for each
distance segment on a bar graph and I wanted to make it selectable for
each runner in the marathon. I later decided to make a second selectable
pull down menu so you can compare two runners information to each other.
To prepare the data I had to filter out all the missing or bad data. I
also had to cut down the size of my data frame to 300 because large
sizes were causing errors.
This map allows an interesting story , you can select two
different runners. You can compare their different times at each
distance. On the left side you get personal information about the runner
such as name, sex, country of origin and age. I used up nearly all the
variable information in the dataframe and feel I represented it well in
the graph. I had difficulty with the dataframe at full size and had to
limit the graph to the top 300 participants. I think I was running out
of memory on my computer with a larger dataset, but I am not
sure.
The interactive visualization is fairly self explanatory On the
left in a clearly marked box you can select between two drop menus. The
names for the top 300 runners are in each menu. When you select
participant their information is listed below and the graph to right is
updated to display each runners times per distance run along with their
pace. You can then directly compare two runners. I chose bar graphs
because they easily display the information and fill up the available
space to make it easy to see. I kept the rest of the graph simple with
easy to understand legend and labels and used a minimal theme. I chose
the colors yellow and blue because they are the colors of the Boston
Marathon and very close to being complimentary colors. I decided on
changing from seconds to minutes because people understand minutes in
large numbers more than seconds.
LS0tDQp0aXRsZTogIkRhdGEgVmlzdWFsaXphdGlvbiAtIE1pbmktUHJvamVjdCAyIg0KYXV0aG9yOiAiQWxleGFuZGVyIEh1Z2hlcyBgYWh1Z2hlczMzMDBAZmxvcmlkYXBvbHkuZWR1YCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCi0tLQ0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh1c21hcCkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoYnJvb20pDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCmBgYHtyfQ0KIyMjIFJlYWQgaW4gZGF0YQ0KbWFyYXRob25fdXNhX3NleF9wYWNlIDwtIHJlYWRfY3N2KCJkYXRhL21hcmF0aG9uX3VzYV9zZXhfcGFjZS5jc3YiKQ0KDQojIyMgY3JlYXRlIGEgY2hvcm9wbGV0aA0KcCA8LSBwbG90X3VzbWFwKGRhdGEgPSBtYXJhdGhvbl91c2Ffc2V4X3BhY2UsIHZhbHVlcyA9ICJudW1iZXIiLCBjb2xvciA9ICJibGFjayIsKStzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKG1pbihtYXJhdGhvbl91c2Ffc2V4X3BhY2UkbiksIG1heChtYXJhdGhvbl91c2Ffc2V4X3BhY2UkbikpKSsgIHNjYWxlX2ZpbGxfY29udGludW91cygNCiAgICBsb3cgPSAiI0ZFRUJFNyIsIGhpZ2ggPSAicmVkIiwgbmFtZSA9ICJUb3RhbCIsIGxhYmVsID0gc2NhbGVzOjpjb21tYQ0KICApICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikrDQogIGZhY2V0X3dyYXAofiBTZXgsbmNvbCA9IDEsbGFiZWxsZXIgPSBhc19sYWJlbGxlcihjKCdGJyA9ICJOdW1iZXIgb2YgRmVtYWxlIFBhcml0aWNwYW50cyIsICdNJyA9ICJOdW1iZXIgb2YgTWFsZSBQYXJ0aWNpcGFudHMiKSkpICtnZ3RpdGxlKGxhYmVsID0gIkJvc3RvbiBNYXJhdGhvbiAyMDE3IikNCg0KcDI8LXAgKyB0aGVtZSgNCiAgbGVnZW5kLnBvc2l0aW9uID0gYygxLCAuMyksIA0KICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiwgY29sb3VyID0gTkEpLA0KICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksDQogc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE1KSwNCiBwYW5lbC5zcGFjaW5nID0gdW5pdCgyLCAibGluZXMiKSwNCiAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KCJTdGF0ZSBvZiBQYXJ0aWNpcGFudHMgT3JpZ2luIikNCiANCikNCiNnZ3Bsb3RseShwMikgDQpgYGANCg0KDQojIyMjbW9kZWwNCg0KYGBge3J9DQoNCiMjIyByZWFkIGluIGFuZCBwcm9jZXNzIGRhdGENCm1hcmF0aG9uIDwtIHJlYWRfY3N2KCJkYXRhL21hcmF0aG9uLmNzdiIpDQptYXJhdGhvbiA8LSBuYS5vbWl0KG1hcmF0aG9uKQ0KbWFyYXRob24kSGFsZjwtIGhtcyhtYXJhdGhvbiRIYWxmKQ0KbWFyYXRob24kT2ZmaWNpYWxUaW1lPC0gaG1zKG1hcmF0aG9uJE9mZmljaWFsVGltZSkNCm1hcmF0aG9uJHRlbks8LSBobXMobWFyYXRob24kdGVuSykNCm1hcmF0aG9uJHRoaXJ0eUs8LSBobXMobWFyYXRob24kdGhpcnR5SykNCm1hcmF0aG9uJFBhY2U8LSBobXMobWFyYXRob24kUGFjZSkNCg0KbWFyYXRob24kSGFsZjwtIGFzLm51bWVyaWMobWFyYXRob24kSGFsZikNCm1hcmF0aG9uJE9mZmljaWFsVGltZTwtIGFzLm51bWVyaWMobWFyYXRob24kT2ZmaWNpYWxUaW1lKQ0KbWFyYXRob24kdGVuSzwtIGFzLm51bWVyaWMobWFyYXRob24kdGVuSykNCm1hcmF0aG9uJHRoaXJ0eUs8LSBhcy5udW1lcmljKG1hcmF0aG9uJHRoaXJ0eUspDQptYXJhdGhvbiRQYWNlPC0gYXMubnVtZXJpYyhtYXJhdGhvbiRQYWNlKQ0KDQpgYGANCg0KYGBge3J9DQojIyMgY3JlYXRlIG1vZGVscw0KbTJfbW9kZWwgPC0gbG0oT2ZmaWNpYWxUaW1lIH4gdGVuSyArIEhhbGYgKyB0aGlydHlLLA0KICAgICAgICAgICAgICAgICAgICBkYXRhID0gbWFyYXRob24pDQp0aWR5KG0yX21vZGVsKQ0KbTJfY29lZnMgPC0gdGlkeShtMl9tb2RlbCwgY29uZi5pbnQgPSBUUlVFKSAlPiUgDQogIGZpbHRlcih0ZXJtICE9ICIoSW50ZXJjZXB0KSIpICANCiNtMl9jb2Vmcw0KbTNfbW9kZWwgPC0gbG0oT2ZmaWNpYWxUaW1lIH4gdGVuSyArIEhhbGYgKyB0aGlydHlLK0FnZSwNCiAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG1hcmF0aG9uKQ0KdGlkeShtM19tb2RlbCkNCm0zX2NvZWZzIDwtIHRpZHkobTNfbW9kZWwsIGNvbmYuaW50ID0gVFJVRSkgJT4lIA0KICBmaWx0ZXIodGVybSAhPSAiKEludGVyY2VwdCkiKSAgDQojbTNfY29lZnMNCmBgYA0KDQpgYGB7cn0NCiMjI2NyZWF0ZSBjb2VmZmljZW50IHBsb3QNCmxhYmxlczI8LWMoIjMwSyIsIjEwSyIsICJIYWxmIFJhY2UiLCJBZ2UiKQ0KDQpwY288LWdncGxvdChtM19jb2VmcywNCiAgICAgICBhZXMoeCA9IGVzdGltYXRlLCANCiAgICAgICAgICAgeSA9IGZjdF9yZXYodGVybSkpKSArDQogIGdlb21fcG9pbnRyYW5nZShhZXMoeG1pbiA9IGNvbmYubG93LCANCiAgICAgICAgICAgICAgICAgICAgICB4bWF4ID0gY29uZi5oaWdoLCBjb2xvcj1mY3RfcmV2KHRlcm0pKSxzaXplPS43NSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCANCiAgICAgICAgICAgICBjb2xvciA9ICJwdXJwbGUiKSArIA0KICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIpKw0KICB0aGVtZV9taW5pbWFsKCkrbGFicyh0aXRsZSA9ICJMaW5lYXIgTW9kZWwgQ29lZmZpY2VudHMgZm9yIEZpbmlzaCBUaW1lIiwgeD0gIkVzdGltYXRlIENvZWZmaWNlbnQiLCB5PSJEaXN0YW5jZSBSdW4iKStzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lPSJEaXN0YW5jZSBSdW4iLCBsYWJlbHM9bGFibGVzMikrc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHM9bGFibGVzMikNCiNwY28NCmBgYA0KDQoNCg0KYGBge3J9DQpnZ3Bsb3RseShwMikgDQpgYGANCiMjIFNwYXRpYWwgVmlzdWFsaXphdGlvbg0KDQoxLiAgV2hhdCBJIG9yaWdpbmFsbHkgd2FudGVkIHRvIG1ha2Ugd2FzIGEgd29ybGQgbWFwIHNob3dpbmcgdGhlIHBhcnRpY2lwYW50cyBvcmlnaW5zLiBIb3dldmVyIHdoZW4gZ29pbmcgdGhyb3VnaCB0aGUgZGF0YSBpdCBiZWNvbWUgYXBwYXJlbnQgdGhhdCB0aGVyZSB3YXNuJ3QgaGlnaCBudW1iZXIgcGFydGljaXBhbnRzIHJlcHJlc2VudGVkIG91dHNpZGUgdGhlIFVTQSBpbiBjb21wYXJpc29uIHRvIGluc2lkZSB0aGUgVVNBLiBTbyBJIHN3aXRjaGVkIHRvIGEgVVNBIG1hcCBhbmQgZGVjaWRlZCB0byBzaG93IHRoZSBwYXJ0aWNpcGFudHMgYnkgc3RhdGUuIEkgZnVydGhlciBkaXZpZGVkIHRoZSBkYXRhIGJ5IFNleCB0byBzZWUgaWYgdGhlcmUgd2VyZSBhbnkgdmlzdWFsIGRpZmZlcmVuY2VzLiBUaGUgc3RlcHMgSSB0b29rIHdlcmUgZmlsdGVyaW5nIG91dCB0aGUgbm9uIFVTQSBwYXJ0aWNpcGFudHMgYW5kIHRoZW4gZnVydGhlciBkaXZpZGluZyB0aGVtIHVwIGJ5IHNleC4gSSB0aGVuIHN1bW1lZCB0aGUgYW1vdW50IG9mIGVhY2ggcGVyIHN0YXRlIGFuZCBjcmVhdGVkIGEgbmV3IGRhdGEgZnJhbWUgdG8gZ3JhcGggdGhlIGRhdGEuIEZpbmFsbHkgSSB3YW50ZWQgdG8gaGF2ZSBzb21ldGhpbmcgaW50ZXJhY3RpdmUgc28gSSBkZWNpZGVkIHRvIHVzZSBnZ3Bsb3RseSBzbyB5b3UgY2FuIHNlZSB0aGUgaW5kaXZpZHVhbCBudW1iZXJzIHBlciBzdGF0ZS4NCg0KMi4gIExvb2tpbmcgYXQgdGhpcyBtYXAgeW91IGNhbiBzZWUgdHdvIHRoaW5ncy4gVGhhdCB0aGUgZ2VuZXJhbCBkaXN0cmlidXRpb24gb2YgbWFsZSBhbmQgZmVtYWxlIHBhcnRpY2lwYW50cyBpcyB2ZXJ5IHNpbWlsYXIgYXMgdGhlIGNvbG9ycyBmb3IgZWFjaCBzdGF0ZSBsb29rIHNpbWlsYXIuIEFsc28geW91IGNhbiBzZWUgd2hpY2ggc3RhdGVzIGhhdmUgdGhlIG1vc3QgcGFydGljaXBhbnRzIHdpdGggTWFzc2FjaHVzZXR0cyBoYXZpbmcgdGhlIG1vc3QuIFRoaXMgbWFrZXMgc2Vuc2UgYmVjYXVzZSB0aGUgbWFyYXRob24gaXMgaG9zdGVkIGluIEJvc3Rvbi4gSG93ZXZlciB3aGF0cyBpbnRlcmVzdGluZyB0aGUgc2Vjb25kIHN0YXRlIGlzIENhbGlmb3JuaWEuIEkgdGhpbmsgdGhpcyBpcyBpbnRlcmVzdGluZyBiZWNhdXNlIENhbGlmb3JuaWEgaXMgc28gZmFyIGF3YXkgZnJvbSBNYXNzYWNodXNldHRzLiBJdCdzIGFsc28gZnVuIHRvIHNlZSB0aGF0IHRoZXkgYWxzbyBoYWQgcGFydGljaXBhbnRzIGZyb20gQWxhc2thIGFuZCBIYXdhaWkuDQoNCjMuICBJIGtlcHQgdGhlIGRlc2lnbiBzaW1wbGUgYW5kIHVzZWQgYSBiYXNlIHJlZCBjb2xvciB0byBtYWtlIHRoZSBwb3B1bGF0aW9ucyBzdGFuZCBvdXQgbW9yZSwgYW5kIGtlcHQgaXQgdG8gb25lIGNvbG9yLiBJIG1hZGUgdGhlIHRpdGxlIGxlZnQgYWxpZ25lZCBiZWNhdXNlIHRoZSB2aWV3ZXJzIGV5ZXMgdGVuZCB0byB2aWV3IHRoZSBsZWZ0LiBJIHVzZWQgYSBmYWNldCBzdHlsZSBncmFwaCB0byBzaG93IHNpZGUgYnkgc2lkZSB0aGUgbWFsZSBhbmQgZmVtYWxlIHBhcnRpY2lwYW50cyBpbiBhIHdheSB0aGF0IHdhcyBlYXN5IHRvIHNlZS4gSSB1c2VkIGdncGxvdHkgdG8gbWFrZSB0aGUgbWFwIGludGVyYWN0aXZlIHNvIHlvdSBjYW4gaG92ZXIgb3ZlciBldmVyeSBwbG90IGFuZCBzZWUgdGhlIG51bWJlcnMuIFRoaXMgZHJhd3MgaW4gdGhlIHVzZXIgdG8gdXNlIHRoZSBtYXAuDQoNCmBgYHtyfQ0KZ2dwbG90KCkgKw0KICBnZW9tX3Ntb290aChhZXMoeCA9IHRlbkssIHkgPSBPZmZpY2lhbFRpbWUpLCBkYXRhID0gbTJfbW9kZWwsIA0KICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQ0IikgKyANCiAgZ2VvbV9zbW9vdGgoYWVzKHggPSBIYWxmLCB5ID0gT2ZmaWNpYWxUaW1lKSwgZGF0YSA9IG0yX21vZGVsLCANCiAgICAgICAgICAgICAgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiYmx1ZTQiKSArIA0KICBnZW9tX3Ntb290aChhZXMoeCA9IHRoaXJ0eUssIHkgPSBPZmZpY2lhbFRpbWUpLCBkYXRhID0gbTJfbW9kZWwsIA0KICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJncmVlbjQiKSArIA0KICBnZW9tX3BvaW50KGFlcyh4ID0gdGVuSywgeSA9IE9mZmljaWFsVGltZSksIGRhdGEgPSBtMl9tb2RlbCwgY29sb3IgPSAicmVkIixhbHBoYSA9IDAuMDIpKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gSGFsZiwgeSA9IE9mZmljaWFsVGltZSksIGRhdGEgPSBtMl9tb2RlbCwgY29sb3IgPSAiYmx1ZSIsYWxwaGEgPSAwLjAyKSArDQogIGdlb21fcG9pbnQoYWVzKHggPSB0aGlydHlLLCB5ID0gT2ZmaWNpYWxUaW1lKSwgZGF0YSA9IG0yX21vZGVsLCBjb2xvciA9ICJncmVlbiIsYWxwaGEgPSAwLjAyKSsgDQphbm5vdGF0ZSgndGV4dCcsIHggPSA1MTAwLCB5ID0gMjcwMDAsIGxhYmVsID0gJ1RlbiBLJyxzaXplID0gNSxhbmdsZT0nNjgnLCBjb2xvcj0gJ3JlZDQnKSsgDQphbm5vdGF0ZSgndGV4dCcsIHggPSAxMTAwMCwgeSA9IDI1NTAwLCBsYWJlbCA9ICdIYWxmIFJhY2UnLHNpemUgPSA1LGFuZ2xlPSc1MScsIGNvbG9yPSAnYmx1ZTQnKSsgDQphbm5vdGF0ZSgndGV4dCcsIHggPSAxODAwMCwgeSA9IDI3NTAwLCBsYWJlbCA9ICdUaHJpdHkgSycsc2l6ZSA9IDUsYW5nbGU9JzQxJywgY29sb3I9ICdncmVlbjQnKStsYWJzKA0KICB0aXRsZSA9ICJMaW5lYXIgTW9kZWwgTGluZSBmb3IgT2ZmaWNhbCBUaW1lIGJ5IERpc3RhbmNlIFRpbWUiLCB4PSAiRGlzdGFuY2UgVGltZSBpbiBTZWNvbmRzIiwgeT0iRmluaXNoIFRpbWUgaW4gU2Vjb25kcyIpK3RoZW1lX21pbmltYWwoKQ0KDQoNCmBgYA0KDQojIyBMaW5lYXIgTW9kZWwgTGluZSBQbG90DQoNCjEuICBGb3IgdGhlIG1vZGVsIEkgb3JpZ2luYWxseSBwbGFuZWQgdG8gY3JlYXRlIGEgbGluZSB3aXRoIGdlb21fc21vb3RoIGFuZCBhIGxpbmVhciBtb2RlbC4gSSBjcmVhdGVkIGEgIGxpbmVhciBtb2RlbCB0aGVuIHVzZWQgdGhlIGxpbmVhciBtb2RlbCBkYXRhIHRvIGRyYXcgdGhyZWUgbGluZXMgd2l0aCBpdHMgYXNzb2NpYXRlZCBwbG90IGNsb3VkLiBJIGFsc28gaGFkIHRvIGNvbnZlcnQgdGhlIHRpbWUgdG8gc2Vjb25kcy4gSSBhbHNvIG9yaWdpbmFsbHkgd2FudGVkIHRvIHBsb3QgYWdlIGJ1dCBpdCBkaWRuJ3QgdHVybiBvdXQgZ29vZC4NCg0KMi4gIExvb2tpbmcgYXQgdGhlIGRhdGEgeW91IGNhbiBzZWUgdGhlIHBsb3QgY2xvdWQgZm9yIHRoZSB0aHJlZSBkaWZmZXJlbnQgZGlzdGFuY2VzIG92ZXIgRmluaXNoIHRpbWUuIFlvdSBjYW4gc2VlIHdoZXJlIGVhY2ggZGlzdGFuY2UgYXMgYSBsaW5lYXIgbW9kZWwgYW5kIGhvdyBpdCBhc3NvY2lhdGVzIHdpdGggd2hhdCBpdCBwcmVkaWN0cyB3aGVyZSB0aGUgZmluaXNoIHRpbWUgc2hvdWxkIGJlIGNvbXBhcmVkIHRvIHRoZSB0aW1lIGF0IHRoZSBhc3NvY2lhdGVkIGRpc3RhbmNlLiBZb3UgY2FuIHNlZSB0aGUgc2xvcGVzIG9mIHRoZSBwcmVkaWN0ZWQgbGluZXMuIFRoZSBzdG9yeSB5b3UgY2FuIHRlbGwgaGVyZSBpcyB5b3UgY2FuIGZvbGxvdyB0aGUgbGluZSBhbmQgc2VlIGlmIHlvdSBwYXNzZWQgYSBkaXN0YW5jZSBhdCB4IHRpbWUgeW91ciBmaW5pc2ggdGhlbSB3aWxsIGxpa2VseSBiZSB5IHRpbWUuIEEgcnVubmVyIGNhbiB1c2UgdGhpcyB0byB0YXJnZXQgdGltZXMgdGhleSBuZWVkIHRvIG1lZXQuIFRoaXMgaXMgZm9sbG93ZWQgZm9yIGVhY2ggb2YgdGhlIHRocmVlIGRpc3RhbmNlcy4gSSBoYWQgZGlmZmljdWx0eSBoZXJlIGFkZGluZyBBZ2UgYXMgYSBjb21wb25lbnQgaXQgZG9lc24ndCBzZWVtIHRvIGNyZWF0ZSBhIHVzYWJsZSBsaW5lLg0KDQozLiAgSSBjb250aW51ZWQgdG8ga2VlcCB0aGUgZGVzaWduIHNpbXBsZSB3aXRoIGJyaWdodCBjb2xvcnMgdG8gY2xhc2ggYWdhaW5zdCB0aGUgd2hpdGUgYmFja2dyb3VuZC4gSSdtIGEgZmFuIG9mIHRoZW1lX21pbmltYWwgYW5kIHRoaW5rIGl0IGRvZXMgYSBnb29kIGpvYiBvZiBkZWNsdXR0ZXJpbmcgdGhlIGdyYXBoLiBJIGFkZGVkIGEgb3BhY2l0eSB0byB0aGUgcGxvdCBwb2ludHMgYmVjYXVzZSB0aGV5IHdlcmUgc28gdGhpY2sgeW91IGNvdWxkbid0IHNlZSB0aGUgbGluZXMuIEZvciBlYWNoIGxpbmUgSSBhZGRlZCBhbiBhbm5vdGF0aW9uIHRvIGlkZW50aWZ5IHdoaWNoIGxpbmUgZ29lcyB0byB3aXRoIHZhcmlhYmxlIGRpc3RhbmNlLg0KDQpgYGB7cn0NCnBjbw0KYGBgDQoNCiMjIE1vZGVsIFZpc3VhbGl6YXRpb24gQ29lZmZpY2llbnQgUGxvdA0KDQoxLiAgRm9yIHRoZSBtb2RlbCBJIG9yaWdpbmFsbHkgcGxhbmVkIHRvIGNyZWF0ZSBhIGNvZWZmaWNpZW50IHBsb3QuIEkgd2FudGVkIHRvIGhhdmUgbW9yZSBlbGVtZW50cyBvcmlnaW5hbGx5IGJ1dCBJIGRlY2lkZWQgdG8ga2VlcCBpdCBzaW1wbGUgYW5kIGxpbWl0IGl0IHRvIGZvdXIgcGxvdCBlbGVtZW50cywgZWFybHkgaW4gdGhlIHJhY2UsIG1pZGRsZSBvZiB0aGUgcmFjZSBhbmQgbGF0ZSBpbiB0aGUgcmFjZSBhbmQgZmluYWxseSBhZ2UuIEkgZm91bmQgdGhhdCBhZGRpbmcgbW9yZSBkaXN0YW5jZXMgd2FzIHNvbWV3aGF0IHJlZHVuZGFudCBhbmQgY29tcGxpY2F0ZWQgdGhlIG1vZGVsLiBUaGUgc3RlcHMgSSB0b29rIHdlcmUgcnVubmluZyB0aGUgdmFyaWFibGVzIHRocm91Z2ggYSBsaW5lYXIgbW9kZWwsIHRoZW4gZ2V0dGluZyB0aGUgY29lZmZpY2llbnRzIGFuZCBjb252ZXJ0aW5nIHRoZSBpbmZvcm1hdGlvbiBpbnRvIHRvIHRpZHkgZGF0YS4NCg0KMi4gIExvb2tpbmcgYXQgdGhpcyBtYXAgeW91IGNhbiBzZWUgdGhlIGNvZWZmaWNpZW50cyBhbmQgaXQgaGFzIGEgdmVydGljYWwgbGluZSBhdCB6ZXJvLiBQb2ludHMgdGhhdCBhcmUgY2xvc2UgdG8gdGhlIHplcm8gZG9uJ3QgaGF2ZSBtdWNoIGJlYXJpbmcgb24gdGhlIG91dGNvbWUuIExvb2tpbmcgYXQgdGhlIHBsb3RzIHlvdSBjYW4gc2VlIHRoYXQgMTBLIGlzIGNsb3NlIHRvIHRoZSB6ZXJvIGxpbmUuIFlvdSBjYW4gYWxzbyBzZWUgdGhhdCBIYWxmIHJhY2UgaGFzIGEgdmFsdWUgb2YgLTEuMyB3aGljaCBoYXMgYSBuZWdhdGl2ZSBpbmZsdWVuY2Ugb24gdGhlIG91dGNvbWUgYW5kIHRoYXQgMzBLIGlzIDIuMyBwb3NpdGl2ZSBhbmQgaGFzIHZlcnkgc3Ryb25nIGJlYXJpbmcgb24gdGhlIG92ZXJjb21lIG9mIHRoZSBGaW5pc2ggVGltZS4gVGhlIFN0b3J5IGhlcmUgaXMgdGhhdCBob3cgeW91IGRvIGVhcmx5IGluIHRoZSByYWNlIGhhcyBtdWNoIGxlc3MgZWZmZWN0IG9uIHlvdXIgZmluaXNoaW5nIHRpbWUgdGhhbiBob3cgeW91IGRvIGxhdGVyIGluIHRoZSByYWNlLiBPbmUgbGFzdCBjb2VmZmljaWVudCBJIHRocmV3IGluIGhlcmUgZm9yIHRoZSBncmFwaCBpcyBBZ2UsIHlvdSBzZWUgdGhhdCBBZ2UgYWdlIGhhcyBsYXJnZSBiZWFyaW5nIG9uIHlvdXIgRmluaXNoIFRpbWUuIERpZmZpY3VsdGllcyBJIGhhZCB3ZXJlIHRoZSBsaW5lYXIgbW9kZWwgZnVuY3Rpb24gaW4gUiB3b3VsZCBub3QgdGFrZSBpdCBpbiB0aW1lIHByb3Blcmx5IEkgaGFkIHRvIGNoYW5nZSBhbGwgdGhlIHRpbWVzIHRvIHNlY29uZHMuDQoNCjMuICBBZ2FpbiBJIGtlcHQgZGVzaWduIG9mIHRoZSBncmFwaCBzaW1wbGUuIEkgaGF2ZSBhIGxpbmUgaW4gdGhlIGdyYXBoIHRvIGVhc2lseSBzaG93IHdoZXJlIHplcm8gaXMuIHRoZSBwb2ludHMgYXJlIGxhcmdlIGFuZCBlYXN5IHRvIHNlZS4gVGhlIHRoZW1lIHVzZWQgaGVyZSBpcyBhIG1pbmltYWwgdGhlbWUuIEkgdXNlZCBhIFNFVDIgcGFsZXR0ZSB0byBtYWtlIHRoZSBjb2xvcnMgcG9wIGFnYWluc3QgdGhlIHdoaXRlIGJhY2tncm91bmQuDQoNCiMjIEludGVyYWN0aXZlIFZpc3VhbGl6YXRpb24NCg0KIyMjIyBHbyB0byBJbnRlcmFjdGl2ZV9WaXouUiBhbmQgc2VsZWN0IHJ1biBhcHAgdG8gbG9hZCB1cCBpbnRlcmFjdGl2ZSBiYXIgZ3JhcGguIEJlbG93IGlzIGEgc2NyZWVuc2hvdCBvZiB0aGUgYXBwIGZvciByZWZlcmVuY2UgcHVycG9zZXMuDQoNCiFbXShpbnRlcmFjdGl2ZV9zY3JlZW5zaG90LnBuZykNCg0KKioqU2hpbnkgQXBwIHJlcXVpcmVzIGxvYWRpbmcgdXAqKioNCg0KKipHbyB0byBJbnRlcmFjdGl2ZV9WaXouUiBhbmQgc2VsZWN0IHJ1biBhcHAgdG8gbG9hZCB1cCBTaGlueSBpbnRlcmFjdGl2ZSBiYXIgZ3JhcGguIEFib3ZlIGlzIGEgc2NyZWVuc2hvdCBvZiB0aGUgYXBwIGZvciByZWZlcmVuY2UgcHVycG9zZXMuKioNCg0KMS4gIEZvciBteSBmaW5hbCB2aXN1YWxpemF0aW9uIEkgd2FudGVkIHRvIGNyZWF0ZSBhIHNoaW55IGFwcGxpY2F0aW9uLiBJIGRlY2lkZWQgb24gZGlzcGxheWluZyB0aGUgcnVubmluZyBpbmZvcm1hdGlvbiBmb3IgZWFjaCBkaXN0YW5jZSBzZWdtZW50IG9uIGEgYmFyIGdyYXBoIGFuZCBJIHdhbnRlZCB0byBtYWtlIGl0IHNlbGVjdGFibGUgZm9yIGVhY2ggcnVubmVyIGluIHRoZSBtYXJhdGhvbi4gSSBsYXRlciBkZWNpZGVkIHRvIG1ha2UgYSBzZWNvbmQgc2VsZWN0YWJsZSBwdWxsIGRvd24gbWVudSBzbyB5b3UgY2FuIGNvbXBhcmUgdHdvIHJ1bm5lcnMgaW5mb3JtYXRpb24gdG8gZWFjaCBvdGhlci4gVG8gcHJlcGFyZSB0aGUgZGF0YSBJIGhhZCB0byBmaWx0ZXIgb3V0IGFsbCB0aGUgbWlzc2luZyBvciBiYWQgZGF0YS4gSSBhbHNvIGhhZCB0byBjdXQgZG93biB0aGUgc2l6ZSBvZiBteSBkYXRhIGZyYW1lIHRvIDMwMCBiZWNhdXNlIGxhcmdlIHNpemVzIHdlcmUgY2F1c2luZyBlcnJvcnMuDQoNCjIuICBUaGlzIG1hcCBhbGxvd3MgYW4gaW50ZXJlc3Rpbmcgc3RvcnkgLCB5b3UgY2FuIHNlbGVjdCB0d28gZGlmZmVyZW50IHJ1bm5lcnMuIFlvdSBjYW4gY29tcGFyZSB0aGVpciBkaWZmZXJlbnQgdGltZXMgYXQgZWFjaCBkaXN0YW5jZS4gT24gdGhlIGxlZnQgc2lkZSB5b3UgZ2V0IHBlcnNvbmFsIGluZm9ybWF0aW9uIGFib3V0IHRoZSBydW5uZXIgc3VjaCBhcyBuYW1lLCBzZXgsIGNvdW50cnkgb2Ygb3JpZ2luIGFuZCBhZ2UuIEkgdXNlZCB1cCBuZWFybHkgYWxsIHRoZSB2YXJpYWJsZSBpbmZvcm1hdGlvbiBpbiB0aGUgZGF0YWZyYW1lIGFuZCBmZWVsIEkgcmVwcmVzZW50ZWQgaXQgd2VsbCBpbiB0aGUgZ3JhcGguIEkgaGFkIGRpZmZpY3VsdHkgd2l0aCB0aGUgZGF0YWZyYW1lIGF0IGZ1bGwgc2l6ZSBhbmQgaGFkIHRvIGxpbWl0IHRoZSBncmFwaCB0byB0aGUgdG9wIDMwMCBwYXJ0aWNpcGFudHMuIEkgdGhpbmsgSSB3YXMgcnVubmluZyBvdXQgb2YgbWVtb3J5IG9uIG15IGNvbXB1dGVyIHdpdGggYSBsYXJnZXIgZGF0YXNldCwgYnV0IEkgYW0gbm90IHN1cmUuDQoNCjMuICBUaGUgaW50ZXJhY3RpdmUgdmlzdWFsaXphdGlvbiBpcyBmYWlybHkgc2VsZiBleHBsYW5hdG9yeSBPbiB0aGUgbGVmdCBpbiBhIGNsZWFybHkgbWFya2VkIGJveCB5b3UgY2FuIHNlbGVjdCBiZXR3ZWVuIHR3byBkcm9wIG1lbnVzLiBUaGUgbmFtZXMgZm9yIHRoZSB0b3AgMzAwIHJ1bm5lcnMgYXJlIGluIGVhY2ggbWVudS4gV2hlbiB5b3Ugc2VsZWN0IHBhcnRpY2lwYW50IHRoZWlyIGluZm9ybWF0aW9uIGlzIGxpc3RlZCBiZWxvdyBhbmQgdGhlIGdyYXBoIHRvIHJpZ2h0IGlzIHVwZGF0ZWQgdG8gZGlzcGxheSBlYWNoIHJ1bm5lcnMgdGltZXMgcGVyIGRpc3RhbmNlIHJ1biBhbG9uZyB3aXRoIHRoZWlyIHBhY2UuIFlvdSBjYW4gdGhlbiBkaXJlY3RseSBjb21wYXJlIHR3byBydW5uZXJzLiBJIGNob3NlIGJhciBncmFwaHMgYmVjYXVzZSB0aGV5IGVhc2lseSBkaXNwbGF5IHRoZSBpbmZvcm1hdGlvbiBhbmQgZmlsbCB1cCB0aGUgYXZhaWxhYmxlIHNwYWNlIHRvIG1ha2UgaXQgZWFzeSB0byBzZWUuIEkga2VwdCB0aGUgcmVzdCBvZiB0aGUgZ3JhcGggc2ltcGxlIHdpdGggZWFzeSB0byB1bmRlcnN0YW5kIGxlZ2VuZCBhbmQgbGFiZWxzIGFuZCB1c2VkIGEgbWluaW1hbCB0aGVtZS4gSSBjaG9zZSB0aGUgY29sb3JzIHllbGxvdyBhbmQgYmx1ZSBiZWNhdXNlIHRoZXkgYXJlIHRoZSBjb2xvcnMgb2YgdGhlIEJvc3RvbiBNYXJhdGhvbiBhbmQgdmVyeSBjbG9zZSB0byBiZWluZyBjb21wbGltZW50YXJ5IGNvbG9ycy4gSSBkZWNpZGVkIG9uIGNoYW5naW5nIGZyb20gc2Vjb25kcyB0byBtaW51dGVzIGJlY2F1c2UgcGVvcGxlIHVuZGVyc3RhbmQgbWludXRlcyBpbiBsYXJnZSBudW1iZXJzIG1vcmUgdGhhbiBzZWNvbmRzLg0K